#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gps_location.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "gps_massge.h"

static char* TAG = "EC-01G-UART";
static QueueHandle_t uart1_queue;
static uart_event_t event;


esp_err_t EC_01G_RST(void);
char* EC_01G_CGSN();
esp_err_t EC_01G_GATT(bool enable);
esp_err_t EC_01G_CGDCONT(void);
esp_err_t EC_01G_CGDCONT(void);
esp_err_t EC_01G_CREG(void);
esp_err_t EC_01G_GPS(int out_time_s);
esp_err_t EC_01G_NO_GPS(void);
esp_err_t EC_01G_CGACT(void);

ec_at_type_t EC_AT_FLAG = AT_DEF;

uint8_t* dtmp = NULL;
char* SIM_SN = NULL;

int GPS_MSG_OUT_TIME = 4;
/**
 * @brief 串口接收任务
 *
 *
 * @param pvParameters
 */
static void uart_event_task(void* pvParameters)
{
    size_t buffered_size;
    dtmp = (uint8_t*)malloc(RD_BUF_SIZE);
    char* GNRMC = malloc(256);
    char gnmc_queue[256] = { 0 };
    for (;;) {
        //Waiting for UART event.
        if (xQueueReceive(uart1_queue, (void*)&event, (portTickType)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            switch (event.type) {

                case UART_DATA:
                    uart_read_bytes(UART_NUM_1, dtmp, event.size, portMAX_DELAY);
                    if (strstr((char*)dtmp, "OK") != NULL || strstr((char*)dtmp, "ECRDY") != NULL) {
                        EC_AT_FLAG = AT_OK;
                        ESP_LOGI(TAG, "[UART DATA]: %.*s", event.size, dtmp);
                    }
                    else if (strstr((char*)dtmp, "ERROR") != NULL) {
                        EC_AT_FLAG = AT_ERROR;
                        ESP_LOGI(TAG, "[UART DATA]: %.*s", event.size, dtmp);
                    }

                    if (strstr((char*)dtmp, "$GNRMC") != NULL) {
                        GNRMC = strstr((char*)dtmp, "$GNRMC");
                        memset(gnmc_queue, 0, 256);
                        for (size_t i = 0; GNRMC[i] != '\r'; i++) {
                            gnmc_queue[i] = GNRMC[i];
                        }
                        ESP_LOGI(TAG, "GPS MSG:%s", gnmc_queue);
                        if (strstr(gnmc_queue, "A") != NULL)
                            xQueueSend(gps_massge_queue, gnmc_queue, portMAX_DELAY);
                    }

                    break;
                    //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");

                    uart_flush_input(UART_NUM_1);
                    xQueueReset(uart1_queue);
                    break;
                    //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");

                    uart_flush_input(UART_NUM_1);
                    xQueueReset(uart1_queue);
                    break;
                    //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                    //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                    //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                    //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    uart_get_buffered_data_len(UART_NUM_1, &buffered_size);
                    int pos = uart_pattern_pop_pos(UART_NUM_1);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {

                        uart_flush_input(UART_NUM_1);
                    }
                    else {
                        uart_read_bytes(UART_NUM_1, dtmp, pos, 100 / portTICK_PERIOD_MS);
                        uint8_t pat[2 + 1];
                        memset(pat, 0, sizeof(pat));
                        uart_read_bytes(UART_NUM_1, pat, UART_NUM_1, 100 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                    //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }

        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    free(dtmp);
    free(GNRMC);
    vTaskDelete(NULL);
}
/**
 * @brief 串口1 初始化：9600 8 1 0
 *
 */

static void esp_uart1_init(void)
{
    uart_config_t Ec01UartConfig = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };

    uart_driver_install(UART_NUM_1, 2048, 2048, 10, &uart1_queue, 0);
    uart_param_config(UART_NUM_1, &Ec01UartConfig);
    uart_set_pin(UART_NUM_1, UART_PIN_TX, UART_PIN_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    xTaskCreate(uart_event_task, "uart_event_task", 4096, NULL, 12, NULL);

}
/**
* @brief EC-01G 命令结构体
 *
 */
EC_01G_t ec_01g_setup = {
    .EC_01G_RST = EC_01G_RST,
    .EC_01G_CGSN = EC_01G_CGSN,
    .EC_01G_CGATT = EC_01G_GATT,
    .EC_01G_CGACT = EC_01G_CGACT,
    .EC_01G_CGDCONT = EC_01G_CGDCONT,
    .EC_01G_CREG = EC_01G_CREG,
    .EC_01G_GPS = EC_01G_GPS,
    .EC_01G_NO_GPS = EC_01G_NO_GPS,
};
/**
 * @brief EC-01G 初始化
 *
 */
void EC_01G_Init(void)
{

    esp_uart1_init();
    vTaskDelay(500 / portTICK_RATE_MS);
    ec_01g_setup.EC_01G_RST();
    vTaskDelay(500 / portTICK_RATE_MS);
    SIM_SN = ec_01g_setup.EC_01G_CGSN();
    EC_AT_FLAG = AT_GET_SN_OK;
    ESP_LOGW(TAG, "SN:%s", SIM_SN);
    /** 附着网络 */
    ESP_ERROR_CHECK(ec_01g_setup.EC_01G_CGATT(GATT_ENABLE));
    /** 设置PAN **/
    ESP_ERROR_CHECK(ec_01g_setup.EC_01G_CGDCONT());
    /** 激活网络 **/
    ESP_ERROR_CHECK(ec_01g_setup.EC_01G_CGACT());
    /** 注册网络 **/
    ESP_ERROR_CHECK(ec_01g_setup.EC_01G_CREG());
    /** 开启 GPS **/
    ESP_ERROR_CHECK(ec_01g_setup.EC_01G_GPS(GPS_MSG_OUT_TIME));
    gps_massge_queue_init();
}
/**
 * @brief EC_01G复位
 *
 * @return esp_err_t*
 */
esp_err_t EC_01G_RST(void)
{
    uart_write_bytes(UART_NUM_1, "AT+ECRST\r\n", strlen("AT+ECRST\r\n"));
    ESP_LOGW(TAG, "Send to EC:AT+ECRST\\r\\n");

    while (EC_AT_FLAG != AT_OK) {
        memset(dtmp, 0, 1024);
        uart_write_bytes(UART_NUM_1, "AT+ECRST\r\n", strlen("AT+ECRST\r\n"));
        ESP_LOGW(TAG, "Send to EC:AT+ECRST\\r\\n");
        vTaskDelay(500 / portTICK_RATE_MS);
    }
    memset(dtmp, 0, 1024);
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 读取SIM 卡号
 *
 * @param str
 * @return char*
 */
char sim_SN[15] = { 0 };
char* EC_01G_CGSN()
{

    uart_write_bytes(UART_NUM_1, "AT+CGSN\r\n", strlen("AT+CGSN\r\n"));
    ESP_LOGW(TAG, "Send to EC:AT+CGSN\\r\\n");
    vTaskDelay(500 / portTICK_PERIOD_MS);
    dtmp += 2;
    while (EC_AT_FLAG != AT_OK) vTaskDelay(20 / portTICK_RATE_MS);
    if (dtmp[0] != '\0') {
        stpncpy(sim_SN, (char*)dtmp, 15);
    }
    EC_AT_FLAG = AT_DEF;
    memset(dtmp, 0, 1024);
    return sim_SN;
}
/**
 * @brief 附着网络
 *
 * @param str
 * @return esp_err_t
 */
esp_err_t EC_01G_GATT(bool enable)
{
    if (enable) {
        uart_write_bytes(UART_NUM_1, "AT+CGATT=1\r\n", strlen("AT+CGATT=1\r\n"));
        ESP_LOGW(TAG, "AT+CGATT=1\\r\\n");
    }
    else {
        uart_write_bytes(UART_NUM_1, "AT+CGATT=0\r\n", strlen("AT+CGATT=0\r\n"));
        ESP_LOGW(TAG, "AT+CGATT=0\\r\\n");
    }

    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 设置PAN
 *
 * @return esp_err_t
 */
esp_err_t EC_01G_CGDCONT(void)
{
    uart_write_bytes(UART_NUM_1, "AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n", strlen("AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n"));
    ESP_LOGW(TAG, "AT+CGDCONT=1,\"IP\",\"CMNET\"\\r\\n");
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 激活网络
 *
 * @return esp_err_t
 */
esp_err_t EC_01G_CGACT(void)
{
    uart_write_bytes(UART_NUM_1, "AT+CGACT=1\r\n", strlen("AT+CGACT=1\r\n"));
    ESP_LOGW(TAG, "AT+CGACT=1\\r\\n");
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 注册网络
 *
 * @return esp_err_t
 */
esp_err_t EC_01G_CREG(void)
{
    uart_write_bytes(UART_NUM_1, "AT+CREG=1\r\n", strlen("AT+CREG=1\r\n"));
    ESP_LOGW(TAG, "AT+CREG=1\\r\\n");
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 开启GPS 
 *
 * @param out_time_s 设置GPS 信息打印间隔
 * @return esp_err_t
 */
esp_err_t EC_01G_GPS(int out_time_s)
{
    char send_data[32] = { 0 };
    uart_write_bytes(UART_NUM_1, "AT+GPS=1\r\n", strlen("AT+GPS=1\r\n"));
    ESP_LOGW(TAG, "AT+GPS=1\\r\\n");
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    sprintf(send_data, "AT+GPSRD=%d\r\n", out_time_s);
    uart_write_bytes(UART_NUM_1, send_data, strlen(send_data));
    ESP_LOGW(TAG, "%s", send_data);
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
/**
 * @brief 关闭GPS
 *
 * @return esp_err_t
 */
esp_err_t EC_01G_NO_GPS(void)
{
    uart_write_bytes(UART_NUM_1, "AT+GPS=0\r\n", strlen("AT+GPS=0\r\n"));
    ESP_LOGW(TAG, "AT+GPS=0\\r\\n");
    while (EC_AT_FLAG != AT_OK) {
        vTaskDelay(20 / portTICK_RATE_MS);
        if (EC_AT_FLAG == AT_ERROR) {
            EC_AT_FLAG = AT_DEF;
            return ESP_ERR_NO_MEM;
        }
    }
    EC_AT_FLAG = AT_DEF;
    return ESP_OK;
}
